/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gebze;

import com.asprise.util.jtwain.JTwainException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.gebze.param.Parametre;
import org.gebze.Util.Scanner;

/**
 * Programın Client tarafı
 *
 * @author Özcan ÇAĞIRICI <ozcanca@gebze.bel.tr>
 *
 *
 */
public class GbzClient
        extends GbzBase {

    private boolean baglanti = false;
    private String serverIp;
    private BufferedReader in;
    private Writer out;
    private BufferedReader terminal;//geçici debug için kullanacağız.

    /**
     * Default Constructor. Constructor çağrıldığında program servera bağlanır
     * ve serverdan komut beklemeye başlar.
     */
    public GbzClient() throws Exception {
        clientAyarlariYap();
        terminal = new BufferedReader(new InputStreamReader(System.in));
        Socket soket = new Socket(serverIp, getPortNumber());
        Reader isRead = new InputStreamReader(soket.getInputStream());
        in = new BufferedReader(isRead);
        out = new OutputStreamWriter(soket.getOutputStream());
    }

    /**
     * Clienta ait ayarlar yapilir.
     */
    private void clientAyarlariYap() throws Exception {
        Properties prop = new Properties();
        String fileName = Parametre.CLIENT_CONFIG_FILE_NAME;
        try {
            InputStream is = new FileInputStream(fileName);
            prop.load(is);
        } catch (IOException e) {
            System.out.println("Dosya yuklenirken hata olustu: " + e);
        }
        try {
            serverIp = prop.getProperty("serverIp");
        } catch (NumberFormatException e) {
            System.out.println("serverIp okunamadi: " + e.getMessage());
            return;
        }
        try {
            setPortNumber(Integer.parseInt(prop.getProperty("portNumber")));
        } catch (NumberFormatException e) {
            System.out.println("port_number okunamadi. Varsayilan ayarlarla devam ediliyor.");
        }
    }

    @Override
    public boolean start() throws IOException {
        boolean isConnected = true;
        System.out.println("Serverdan bilgi bekleniyor...");
        do {
            String mesaj = in.readLine();
            System.out.println(mesaj);

            if (mesaj.equals("q")) {
                isConnected = false;
                out.write("client kapanıyor.");
            } else {
                System.out.println("Servera mesaj yazınız.");
                mesaj = terminal.readLine();
                out.write(mesaj + "\n");
                out.flush();
            }
//            if ("p".equals(mesaj)) {
//                dosyaTaraGonder(os);
//            } else {
//                String clientMesaj = clienttanMesajOkuGonder(os);
//                if ("q".equals(clientMesaj)) {
//                    baglanti = false;
//                }
//            }
        } while (isConnected);
        return true;

    }

    /**
     * Serverin tarama istegine karsilik, belgeyi tarar. Belge boyutunu karsi
     * tarafa gonderir.
     *
     * @param os
     */
    private void dosyaTaraGonder(OutputStream os) {
        Scanner scanner = null;
        try {
            scanner = new Scanner();
        } catch (JTwainException ex) {
            Logger.getLogger(GbzClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        byte[] belge = null;
        try {
            belge = scanner.getImage();
        } catch (Exception ex) {
            Logger.getLogger(GbzClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            os.write(belge.length);
        } catch (IOException ex) {
            System.out.println(ex);
        }
        imageParcalaGonder(belge, os);
    }

    /**
     * Clientin mesajlari servera iletilir.
     *
     * @param os
     * @return
     */
    private String clienttanMesajOkuGonder(OutputStream os) {
        System.out.println("Mesaji giriniz: ");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(os));
        String mesaj = null;
        try {
            mesaj = br.readLine();
            wr.write(mesaj);
        } catch (IOException ex) {
            System.out.println("IOException:" + ex);
        }
        return mesaj;
    }

    /**
     * Taranan belgeyi parcalara ayirir.Karsi tarafa (server) gonderir.
     *
     * @param belge
     * @param os
     */
    private void imageParcalaGonder(byte[] belge, OutputStream os) {

        int tamParcaSayisi = belge.length / Parametre.MAX_DATA_PARCA_BOYUTU;
        int artan = belge.length % Parametre.MAX_DATA_PARCA_BOYUTU;
        byte[] artanDizi = new byte[artan + Parametre.PARCA_HEADER_SIZE];
        byte[] parca = new byte[Parametre.MAX_PARCA_BOYUTU];

        for (int i = 0; i < tamParcaSayisi; ++i) {
            parca = getPart(i, Parametre.MAX_DATA_PARCA_BOYUTU, belge);
            try {
                os.write(parca);
            } catch (IOException ex) {
                System.out.println(ex);
            }
        }
        artanDizi = getPart(tamParcaSayisi, artan, belge);
        try {
            os.write(artanDizi);
        } catch (IOException ex) {
            System.out.println(ex);
        }
    }

    private byte[] getPart(int siraSayisi, int okunacakBoyut, byte[] kaynak) {
        int k = 0;
        byte[] parca = new byte[Parametre.MAX_PARCA_BOYUTU];
        byte[] diziSirasi = convertIntTo32Bits(siraSayisi);
        for (int i = 0; i < Parametre.PARCA_HEADER_SIZE; ++i) {
            parca[k++] = diziSirasi[i];
        }
        for (int j = siraSayisi * Parametre.MAX_DATA_PARCA_BOYUTU; j < Parametre.MAX_DATA_PARCA_BOYUTU * siraSayisi + okunacakBoyut; ++j) {
            parca[k++] = kaynak[j];
        }
        return parca;
    }

    /**
     * Integer degerleri, byte arraye donusturur.
     *
     * @param value
     * @return
     */
    private byte[] convertIntTo32Bits(int value) {
        byte[] b = new byte[4];
        for (int i = 0; i < 4; ++i) {
            int offset = (b.length - 1 - i) * 8;
            b[i] = (byte) ((value >>> offset) & 0xFF);
        }
        return b;
    }
}
